from flask import Flask, jsonify
from blueprints.test import test_bp
from blueprints.api import api_bp
from blueprints.user import user_bp
from extensions import db, ma
from settings import BaseSetting
from marshmallow.exceptions import ValidationError
from utils.response_err import Error400, Error401, Error403, Error500
from models.user import User


def create_app():
    app = Flask(__name__)
    app.config.from_object(BaseSetting)
    # 注册蓝本
    blueprint_register(app)
    # 注册拓展
    extensions_register(app)
    # 注册异常处理
    exceptions(app)
    # 注册自定义命令
    cli(app)
    return app


def blueprint_register(app):
    app.register_blueprint(test_bp, url_prefix='/test')
    app.register_blueprint(api_bp, url_prefix='/api')
    app.register_blueprint(user_bp, url_prefix='/user')


def extensions_register(app):
    db.init_app(app)
    ma.init_app(app)


def exceptions(app):
    # 全局捕获 字段验证错误异常 ValidationError
    @app.errorhandler(ValidationError)
    def validation_err(e):
        print(e, e.messages, type(e))
        msg = {k: v[0] for k, v in e.messages.items()}
        return jsonify({'msg': msg})

    @app.errorhandler(Error400)
    def validation_err_400(e):
        return jsonify({'msg': e.to_dict()})

    @app.errorhandler(Error500)
    def validation_err_500(e):
        return jsonify({'msg': e.to_dict()})

    @app.errorhandler(Error403)
    def validation_err_403(e):
        return jsonify({'msg': e.to_dict()})

    @app.errorhandler(Error401)
    def validation_err_401(e):

        return jsonify({'msg': e.to_dict()})

    @app.errorhandler(404)
    def err404(e):
        pass


def cli(app):
    # 数据库初始化
    @app.cli.command('db_init')
    def db_init():
        # from models.api import db
        with app.app_context():
            db.create_all()

    # 数据库重置
    @app.cli.command('db_reset')
    def db_reset():
        # from models.api import db
        with app.app_context():
            db.drop_all()
            db.create_all()
            user = User(username='admin', password='admin123', )
            db.session.add(user)
            db.session.commit()
